import {Component, OnInit} from '@angular/core';
import {Title} from '@angular/platform-browser';
import {Router} from '@angular/router';
import {NzMessageService} from 'ng-zorro-antd/message';
import {from} from 'rxjs';
import {filter} from 'rxjs/operators';
import {Course, ExtendedCourse} from '../course/Course';
import {CourseLoaderService} from '../course/course-loader.service';
import InnerCourses from "../course/inner-course/courses";
import {saveAs} from "file-saver";
import fileDialog from "file-dialog";
import JsZip from "jszip";
import {DBService} from '../db/db.service';
import { v4 as uuidv4 } from 'uuid';

@Component({selector: 'app-manage', templateUrl: './manage.component.html', styleUrls: ['./manage.component.scss']})
export class ManageComponent implements OnInit {

    constructor(private courseLoader : CourseLoaderService, private message : NzMessageService, private router : Router, private title : Title, private db : DBService) {}

    courses : ExtendedCourse[] = [];
    setOfCheckedId = new Set<string>();
    allChecked = false;

    ngOnInit(): void {
        this.title.setTitle('课程管理');
        from(this.courseLoader.courseList()).subscribe((courseList) => {
            from(this.courseLoader.extend(courseList)).subscribe(extended => {
                this.courses = extended;
            });
        })
    }
    onItemChecked(id : string, checked : boolean) {
        if (checked) {
            this.setOfCheckedId.add(id);
        } else {
            this.setOfCheckedId.delete(id);
        }
    }
    onAllChecked(checked : boolean): void {
        if (checked) {
            this.setOfCheckedId = new Set<string>(this.courses.map(x => x.course.id));
        } else {
            this.setOfCheckedId = new Set<string>();
        }
    }
    // 导入内置课程
    isInnerCourseModalVisible = false;
    newCourses : Course[] = [];
    existedCourses : Course[] = [];
    async onInnerCourseModalOk() {
        await this.courseLoader.import (this.newCourses);
        await this.courseLoader.import (this.existedCourses);
        this.isInnerCourseModalVisible = false;
        this.message.success(`已导入${
            this.newCourses.length
        }项，更新${
            this.existedCourses.length
        }项`);
        await this.refreshAll();
    }
    async importInnerCourses() {
        for (const course of InnerCourses) {
            if (await this.courseLoader.exists(course.id)) {
                this.existedCourses.push(course);
            } else {
                this.newCourses.push(course);
            }
        }
        this.isInnerCourseModalVisible = true;
    }
    // 对单选项的操作
    async refreshCourse(id : string) {
        const index = this.courses.findIndex(x => x.course.id === id);
        const newCourse = await this.courseLoader.getExtended(id);
        const temp = [...this.courses];
        if (newCourse) {
            temp[index] = newCourse;
            this.courses = temp;
        }
    }
    async refreshAll() {
        const temp = await this.courseLoader.courseList();
        const extended = await this.courseLoader.extend(temp);
        this.courses = extended;
        // 保留选项
        const newSet: Set<string> = new Set();
        for (const course of this.courses) {
            if (this.setOfCheckedId.has(course.course.id)) {
                newSet.add(course.course.id);
            }
        }
        this.setOfCheckedId = newSet;
    }
    play(course : ExtendedCourse) {
        this.router.navigate(course.url);
    }
    edit(course : ExtendedCourse) {
        this.router.navigate(course.creatorUrl);
    }
    async deleteCourse(course : ExtendedCourse) {
        await this.courseLoader.delete(course.course.id);
        await this.refreshAll();
    }
    async reset(course : ExtendedCourse) {
        await this.courseLoader.reset(course.course.id);
        await this.refreshCourse(course.course.id);
    }
    // 导出
    export(courses : ExtendedCourse[]) {
        const json = JSON.stringify(courses.map(x => x.course));
        saveAs(new Blob([json], {type: 'application/json'}), "courses" + (
            new Date()
        ).toISOString().split('-').join('').split(':').join('').replace('.', '') + ".json");
    }
    async exportData(courses : ExtendedCourse[]) {
        const json = JSON.stringify({
            course: courses.map(x => x.course),
            progress: await this.db.table('courseProgress').toArray(),
            code: await this.db.table('code').toArray()
        });
        saveAs(new Blob([json], {type: 'application/json'}), "progress" + (
            new Date()
        ).toISOString().split('-').join('').split(':').join('').replace('.', '') + ".json");
    }
    // 对选择项的操作
    async deleteSelected() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            for (const id of this.setOfCheckedId) {
                await this.courseLoader.delete(id);
            }
            await this.refreshAll();
        }
    }
    async resetSelected() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            for (const id of this.setOfCheckedId) {
                await this.courseLoader.reset(id);
            }
            await this.refreshAll();
        }
    }
    exportSelectedLoading = false;
    exportSelected() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            this.exportSelectedLoading = true;
            this.export(this.courses.filter(x => this.setOfCheckedId.has(x.course.id)));
            this.exportSelectedLoading = false;
        }
    }
    exportSelectedDataLoading = false;
    exportSelectedData() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            this.exportSelectedDataLoading = true;
            this.exportData(this.courses.filter(x => this.setOfCheckedId.has(x.course.id)));
            this.exportSelectedDataLoading = false;
        }
    }
    exportJupyterNotebookLoading = false;
    async exportJupyterNotebook() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            this.exportJupyterNotebookLoading = true;
            const courses = this.courses.filter(x => this.setOfCheckedId.has(x.course.id));
            const zip = new JsZip();
            const codeIndex = await this.courseLoader.codeIndex();
            courses.forEach(c => {
                zip.file(c.course.name + '.ipynb', c.toNotebook(codeIndex));
            });
            const content = await zip.generateAsync({type: 'blob'})as Blob;
            saveAs(content, "notebook" + (
                new Date()
            ).toISOString().split('-').join('').split(':').join('').replace('.', '') + ".zip")
            this.exportJupyterNotebookLoading = false;
        }
    }
    exportPythonProjectLoading = false;
    async exportPythonProject() {
        if (this.setOfCheckedId.size === 0) {
            this.message.info('未选中课程');
        } else {
            this.exportPythonProjectLoading = true;
            const courses = this.courses.filter(x => this.setOfCheckedId.has(x.course.id));
            const zip = new JsZip();
            const codeIndex = await this.courseLoader.codeIndex();
            courses.forEach(c => {
                zip.folder(c.course.name);
                c.course.page.forEach((p,i)=>{
                    const task = p.task.map(t=>'* ' + t.title).join('\n');
                    zip.file(c.course.name + '/' + (i+1).toString() + p.name + '.md', p.markdown + '\n\n## 任务\n\n' + task);
                    if(c.course.id in codeIndex && i in codeIndex[c.course.id]){
                        zip.file(c.course.name + '/' + (i+1).toString() + p.name + '.py', codeIndex[c.course.id][i]);
                    }else{
                        zip.file(c.course.name + '/' + (i+1).toString() + p.name + '.py', p.code);
                    }
                });
            });
            const content = await zip.generateAsync({type: 'blob'})as Blob;
            saveAs(content, "project" + (
                new Date()
            ).toISOString().split('-').join('').split(':').join('').replace('.', '') + ".zip")
            this.exportPythonProjectLoading = false;
        }
    }
    // 导入课程或进度
    async importCoursesOrProgress() {
        const files = await fileDialog({multiple: false, accept: 'application/json'});
        const file = files[0];
        const fileContent = await file.text();
        const data = JSON.parse(fileContent);
        if (Array.isArray(data)) { // 课程
            if (data.length > 0) {
                await this.courseLoader.import (data);
            }
        } else { // 进度
            await this.courseLoader.importProgress(data);
        }
        await this.refreshAll();
    }
    // 创建课程对话框
    isCreateCourseModalVisible = false;
    createCourseModelId = '';
    createCourseModelName = '';
    createCourse(){
        this.createCourseModelId = uuidv4().toString();
        this.isCreateCourseModalVisible = true;
    }
    async onCreateCourseModalOk(){
        this.isCreateCourseModalVisible = false;
        const course = await this.courseLoader.create(this.createCourseModelName, this.createCourseModelId);
        this.router.navigate(['creator', course.id]);
    }
    onCreateCourseModalCancel(){
        this.isCreateCourseModalVisible = false;
    }
    shouldDisableCreateCourseModal(){
        return !this.createCourseModelId || !this.createCourseModelName;
    }
}
